function co(fn) {
    let gen = fn()
    function next(...args) {
        const { value, done } = gen.next()
        if (done) return value;
        if (value.then) {
            return value.then(res => next(res))
        } else {
            return next(value)
        }
    }
    next()
}


Promise.prototype.myAll = function (...args) {
    let result = []
    new Promise(function (resolve, reject) {
        for (let i = 0; i < args.length; i++) {
            args[i]().then(res => {
                result[i] = res // 优先
                if (result.length == args.length) {
                    return resolve(result)
                }
            }).catch(err => {
                reject(err)
            })
        }
    }, function (err) {
        reject(err)
    })
}

Promise.prototype.myRace = function (...args) {

    new Promise(function (resolve, reject) {
        for (let i = 0; i < args.length; i++) {
            args[i]().then(res => {
                return resolve(res)
            }).catch(err => {
                reject(err)
            })
        }
    }, function (err) {
        reject(err)
    })
}


Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    return this.then(
        value => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
    );
};


class queue {
    constructor() {
        this.cacheList = [];
    }

    add(delay, fn) {
        this.cacheList.push(() => sleep(delay, fn))
        return this;
    }

    async task() {
        this.cacheList.forEach(async (fn) => {
            await fn();
        })
    }

}


class PromiseQueue {
    constructor(options = {}) {
        this.conCurrency = options.conCurrency;
        this.cacheList = [];
        this.count = 0;
    }
    add(fn) {
        // 权重 可以在插入的位置排序
        this.conCurrency.push(fn)
        this.run()
    }

    run() {
        // for (let i = 0; i < array.length; i++) {
            if (!this.cacheList.length || this.count > this.conCurrency) {
                return
            }
            let fn = this.cacheList.shift();
            let promise = fn()
            this.count++
            promise.then(this.complateDone.bind(this)).catch(this.complateDone.bind(this))
        // }
    }

    complateDone(res) {
        this.count--;
        this.run()

    }
}

// 请求重试
function request(url, maxCount = 5){
    return fetch(url).catch(err => maxCount<=0 ? Promise.reject(err): request(url, maxCount-1))
}

// 模拟微任务
function runaMicrotask(func){
    if(typeof Promise === 'function'){
        Promise.resolve().then(func)
        return
    }

    if(typeof MutationObserver === 'function'){
        var ob = new MutationObserver(func)
        var node = document.createTextNode('')
        ob.observe(node, {characterData: true})
        node.data = 1;
        return
    }

    if(process && typeof process.nextTick === 'function'){
        process.nextTick(func)
        return
    }

}